package gggameserver.games;

import gggameserver.exceptions.GGIllegalMoveFormat;
import gggameserver.games.connection.GGConnection;

public abstract class Board {

	public enum GameEndReason {
		NORMAL, TIMEOUT, ILLEGAL_MOVE
	};

	public static final int RESULT_GAME_RUNNING = -1;
	public static final int RESULT_DRAW = 0;

	public static final int PLAYER_FIRST = 1;

	private GameEndReason endReason = GameEndReason.NORMAL;
	private int winner = RESULT_GAME_RUNNING;
	private int initialized_players = 0;
	private int active_player = PLAYER_FIRST;
	private Player[] player;

	// private Result[] result;

	public Board(int num_players) {
		// TODO
		this.player = new Player[num_players];
		// this.result = new Result[num_players];
	}

	public final Player[] getPlayers() {
		return this.player;
	}

	public void addPlayer(Player player) {
		if (this.initialized_players >= this.player.length)
			return; // TODO

		this.player[this.initialized_players++] = player;
		player.setPlayerNumber(this.initialized_players);
	}

	public GameEndReason getGameEndReason() {
		return endReason;
	}

	public boolean isGameOver() {
		return RESULT_GAME_RUNNING != this.winner;
	}

	public int getWinner() {
		return this.winner;
	}

	public Result getPlayerResult(int playerNumber) {
		return new Result(getWinner() == playerNumber ? 1 : 2);
	}

	public void setDraw() {
		this.winner = RESULT_DRAW;
	}

	public void setWinner(int playerNr) {
		if (playerNr < PLAYER_FIRST
				|| (PLAYER_FIRST + player.length - 1) < playerNr)
			throw new IllegalStateException("Illegal winner " + playerNr);

		this.winner = playerNr;
	}

	public void setWinner(Player winner) {
		// TODO
		setWinner(winner.getPlayerNumber());
	}

	public void setLoser(Player loser) {
		// TODO
		Player w = null;
		if (player[0] == loser)
			w = player[1];
		if (player[1] == loser)
			w = player[0];
		setWinner(w);
	}

	public int getActivePlayerNumber() {
		return this.active_player;
	}

	public Player getActivePlayer() {
		return this.player[this.active_player - 1];
	}

	public void moveToNextPlayer() {
		if (this.active_player == this.player.length)
			this.active_player = PLAYER_FIRST;
		else
			this.active_player++;
	}

	public void moveToPlayer(int nr) {
		// TODO
		this.active_player = nr;
	}

	public abstract void makeMove(Move move);

	//

	public void setPlayerConnection(int player_nr, GGConnection con) {
		// TODO
		this.player[player_nr - 1].setConnection(con);
	}

	public Move commandToMove(String command) throws GGIllegalMoveFormat {
		try {
			return commandToMoveSimple(command);
		} catch (Exception e) {
			throw new GGIllegalMoveFormat(command);
		}
	}

	/**  */
	protected abstract Move commandToMoveSimple(String command)
			throws Exception;

	public abstract String moveToCommand(Move move);

	public abstract boolean isLeagal(Move move);

	public void timeout() {
		anormalEnd(GameEndReason.TIMEOUT);
	}

	public void illegalMove() {
		anormalEnd(GameEndReason.ILLEGAL_MOVE);
	}

	private void anormalEnd(GameEndReason reason) {
		this.setLoser(this.getActivePlayer());
		setGameEndReason(reason);
	}

	public void setGameEndReason(GameEndReason reason) {
		if (null == reason)
			throw new IllegalStateException("Game end reason not set");
		endReason = reason;
	}

}
